//
//  XUtils.m
//  LionLibs
//
//  Created by NicholasXu on 11-5-13.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "XUtils.h"

#import "FunctionSet.h"
#import "NameValuePaire.h"
#import "RegexKitLite.h"

@implementation XUtils

static NSMutableDictionary * _encodings = nil;


//Adjust the value.
const int TestEncodingLength = 64;
NSString *EncodingFromXMLData(NSData *data)
{
    if (data.length == 0) {
        return nil;
    }
    
    NSUInteger bufSize = TestEncodingLength;
    if (data.length < TestEncodingLength) {
        bufSize = data.length;
    }
    
    //Get sample data.
    const char *buf = malloc(sizeof(char) * bufSize);
    [data getBytes:(void*)buf length:bufSize];
    NSLog(@"%u [%u, %u] [%u, %u]", '<', *buf, *(buf+1), 0xff, 0xfe);
    
    //Get sample string.
    NSString *test = [XAutorelease([[NSString alloc] initWithBytes:buf length:bufSize encoding:NSASCIIStringEncoding]) lowercaseString];
    //find xml mark
    //err:[ =.-\"?]
    //OK[.?\"= -]
    NSString *XMLTagRegex = @"<\\?(\\w|[\\.\\?\"=\\s-']){0,}\\?>";
    NSRange tagRange = [test rangeOfRegex:XMLTagRegex];
    NSString *XMLTagString = tagRange.length != NSNotFound && tagRange.location < test.length ? [test substringWithRange:tagRange] : @"";
    NSLog(@"\nStart---------\ntest:\n%@", test);
    NSLog(@"rang :%@, found:%@\nEnd---------\n", NSStringFromRange(tagRange), XMLTagString);
    
    //find encoding
    NSString *EncodingTagRegex = @"encoding=(\\w|[-\"='_]){0,}";
    NSRange encRange = [XMLTagString rangeOfRegex:EncodingTagRegex];
    NSString *encString = encRange.length != NSNotFound && encRange.location < XMLTagString.length ? [XMLTagString substringWithRange:encRange] : @"";
    [[encString retain] autorelease];
    NSLog(@"range :%@, encoding :%@", NSStringFromRange(encRange), encString);
    NSLog(@"\n\n---------");
    free((void*)buf);
    
    //find encoding name.
    NSString *encNameTagRegex = @"('|\"){1,}(\\w|-){0,}('|\"){1,}";
    NSRange encNameRange = [encString rangeOfRegex:encNameTagRegex];
    NSString *encName = nil;
    if (encNameRange.location != NSNotFound) {
        encName = [encString substringWithRange:encNameRange];
    }
    NSLog(@"encName:%@",encName);
    //default is utf-8
    if (encName.length < 3) {
        return @"utf-8";
    }
    return [encName substringWithRange:NSMakeRange(1, encName.length - 2)];
}


@synthesize foundSubviews;

+ (void)printArray:(NSArray *)anArray
{
    if (!anArray) {
        NSLog(@"%s print array is null!", __FUNCTION__);
        return;
    }
    int i = 0;
    for (NSObject * obj in anArray) {
        NSLog(@"Class:%@; index:%d; value:[%@]", [obj classForCoder], i, obj);
        i ++;
    }
}

+ (void)printArray:(NSArray *)anArray ToDestinateString:(NSString **)aDestString
{
    NSMutableString * str = [NSMutableString string];
    int  i = 0;
    for (NSObject * obj in anArray) {
        [str appendFormat:@"Class:%@; index:%d; value:%@\n", [obj classForCoder], i, obj];
        i ++;
    }
    (*aDestString) = str;
}

+ (void)printDictionary:(NSDictionary*)anDictionary
{
    NSArray *keys = [anDictionary allKeys];
    for (NSString *key in keys) {
        NSLog(@"key :%@; value:%@", key, [anDictionary valueForKey:key]);
    }
}

+ (BOOL)isRetina
{
    if ([[UIScreen mainScreen] respondsToSelector:@selector(currentMode)]) {
        CGSize screenSize = [UIScreen mainScreen].bounds.size;
        CGSize screenMode = [UIScreen mainScreen].currentMode.size;
        //NSLog(@"%@  %@", NSStringFromCGSize(screenSize), NSStringFromCGSize(screenMode));
        //[XUtils printArray:[UIScreen mainScreen].availableModes];
        return (screenMode.width > screenSize.width);
    }else {
        return NO;
    }
}

+ (UIImage *)loadImageWithName:(NSString *)name Type:(NSString *)type
{
    return [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:name ofType:type]];
}

+ (UIImage *)loadImageWithName:(NSString *)imageName
{
    NSArray *nameCompoents = [imageName componentsSeparatedByString:@"."];
    
    NSString *extname = @"";
    if (nameCompoents.count > 1) {
        extname = [[imageName componentsSeparatedByString:@"."] lastObject];
        assert(extname.length + 1 <= imageName.length);
    }
    NSLog(@"extname :%@", extname);
    NSLog(@"ext:%u  imageName:%u", extname.length, imageName.length);
    
    NSString *name = nil;
    if (nameCompoents.count > 1) {
        name = [imageName substringToIndex:[imageName rangeOfString:[NSString stringWithFormat:@".%@" ,extname]].location];
    }else {
        name = imageName;
    }
    
    NSString *subfix = [XUtils isRetina] ? @"@2x" : @"";
    NSString *path = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@%@", name, subfix] ofType:extname];
    if (path.length == 0) {
        path = [[NSBundle mainBundle] pathForResource:name ofType:extname];
    }
    if (path.length == 0) {
        return nil;
    }
    NSLog(@"image path :%@", path);
    return [UIImage imageWithContentsOfFile:path];
}

+ (void)cancelTimer:(NSTimer **)timer
{
    if ((*timer) != nil) {
        [(*timer) invalidate];
        SafeRelease(*timer);
    }
}

+ (float)osVersion
{
    return [[UIDevice currentDevice] systemVersion].floatValue;
}

#pragma mark - Singletone pattern

static XUtils * __utils__ = nil;
+ (XUtils *) instance {
	if (!__utils__) {
		__utils__ = [[XUtils alloc] init];
	}
	return __utils__;
}

- (id) init
{
	self = [super init];
	if (!_encodings) {
		[self encodingSet];
	}
	return self;
}

#if !ARC_ENABLED
- (oneway void)release
{
}

- (NSUInteger)retainCount
{
    return NSUIntegerMax;
}

- (id)retain
{
    return self;
}

- (id)copy
{
    return self;
}

- (id)autorelease
{
    return self;
}

- (void)dealloc
{
    [super dealloc];
}
#endif

#pragma mark - Util Methods

//- (NSString *)faviconUrlStringFromHtml:(NSString *)htmlContent andUrl:(NSString *)urlString
//{
//    NSString * iconFilter = [NSString stringWithFormat:@"href=\"([a-zA-Z$/.:0-9]){0,}([.]ico)"];
//    
//    NSString * shortcut = [htmlContent stringByMatching:@"shortcut icon"];
//    NSMutableString * iconUrlStr = [NSMutableString string];
//    NSMutableString * rootUrl = [NSMutableString string];
//    NSArray * pathComps = [urlString pathComponents];
//    NSString * iconPath = [htmlContent stringByMatching:iconFilter];
//	//    remove href\" prefix
//    iconPath = [iconPath stringByReplacingOccurrencesOfRegex:@"href[ ]{0,}=[ ]{0,}\"[ ]{0,}" withString:@""];
//	//    NSLog(@"shortcut=%@; iconPath=%@", shortcut, iconPath);
//    [rootUrl appendFormat:@"%@//", [pathComps objectAtIndex:0]];
//    [rootUrl appendFormat:@"%@", [pathComps objectAtIndex:1]];
//	//    NSLog(@"rootUrl=%@;   iconUrlStr=%@", rootUrl, iconUrlStr);
//    if (shortcut) {
//        if (!iconPath) {
//            return nil;
//        }
//        [iconUrlStr setString:iconPath];
//        if (![iconUrlStr stringByMatching:@"^http[s]{0,}"]) {
//            [iconUrlStr insertString:rootUrl atIndex:0];
//        }
//        
//    }else {
//        [iconUrlStr appendFormat:@"%@/favicon.ico", rootUrl];
//    }
//	//    NSLog(@"shortcut:%@  iconUrl:%@", shortcut, iconUrlStr);
//    return iconUrlStr;
//}

- (NSDictionary *)encodingSet
{
	if (!_encodings) {
		_encodings = [NSMutableDictionary dictionary];
		_encodings = [NSMutableDictionary new];
		[_encodings setObject:[NSNumber numberWithUnsignedLong:NSASCIIStringEncoding] forKey:@"ascii"];
		[_encodings setObject:[NSNumber numberWithUnsignedLong:NSUTF8StringEncoding] forKey:@"utf-8"];
		[_encodings setObject:[NSNumber numberWithUnsignedLong:NSUnicodeStringEncoding] forKey:@"unicode"],
		[_encodings setObject:[NSNumber numberWithUnsignedLong:CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGBK_95)] forKey:@"gbk"];
		[_encodings setObject:[NSNumber numberWithUnsignedLong:CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_2312_80)] forKey:@"gb2312"];
		[_encodings setObject:[NSNumber numberWithUnsignedLong:CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000)] forKey:@"gbk18030"];
		[_encodings setObject:[NSNumber numberWithUnsignedLong:CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingBig5)] forKey:@"big5"];
	}
	return _encodings;
}

- (NSString *)findCorrectHtmlStringFrom:(NSData *)dataBuffer andTextEncoding:(NSString *)responseEncoding
{
    
//    NSString * html = [[NSString alloc] initWithData:dataBuffer encoding:NSASCIIStringEncoding];
//    NSString * enc = nil;
//    enc = [html stringByMatching:@"charset=(([a-zA-Z0-9-\"])*)"];
//	enc = [enc stringByReplacingOccurrencesOfRegex:@"\"" withString:@""];
//	enc = [enc stringByReplacingOccurrencesOfRegex:@"charset=" withString:@""];
//	
//	if (!enc) {
//		enc = [html stringByMatching:@"encoding=(([a-zA-Z0-9-\"])*)"];
//		enc = [enc stringByReplacingOccurrencesOfRegex:@"\"" withString:@""];
//		enc = [enc stringByReplacingOccurrencesOfRegex:@"encoding=" withString:@""];
//	}
//
//	enc = [enc lowercaseString];
//	responseEncoding = [responseEncoding lowercaseString];
//    NSLog(@"enc = %@; responseEncoding = %@", enc, responseEncoding/*[html stringByMatching:@"encoding=(([a-zA-Z0-9-\"])*)"]*/);
//    
//    [html release];
    NSString *html = nil;
	NSString *enc = [self findCorrectHtmlEncodingNameFrom:dataBuffer];
    if (!responseEncoding && !enc) {
		html = [[NSString alloc] initWithData:dataBuffer encoding:NSUTF8StringEncoding];
    }else if (responseEncoding) {
        html = [[NSString alloc] initWithData:dataBuffer encoding:[[[self encodingSet] objectForKey:responseEncoding] unsignedLongValue]];
    }else if (enc) {
        html = [[NSString alloc] initWithData:dataBuffer encoding:[[[self encodingSet] objectForKey:enc] unsignedLongValue]];
    }
    return XAutorelease(html);
}

//- (NSString *) findCorrectHtmlEncodingNameFrom:(NSData *) dataBuffer
//{
//    NSString * html = [[NSString alloc] initWithData:dataBuffer encoding:NSASCIIStringEncoding];
//    NSString * enc = nil;
//    
//    if (!enc) {
//        enc = [html stringByMatching:@"charset=(([a-zA-Z0-9-\"'])*)"];
//        enc = [enc stringByReplacingOccurrencesOfRegex:@"\"" withString:@""];
//        enc = [enc stringByReplacingOccurrencesOfString:@"'" withString:@""];
//        enc = [enc stringByReplacingOccurrencesOfRegex:@"charset=" withString:@""];
//        NSLog(@"found charset:%@", enc);
//	}
//    
//	if (!enc) {
//		enc = [html stringByMatching:@"encoding=(([a-zA-Z0-9-\"'])*)"];
//		enc = [enc stringByReplacingOccurrencesOfRegex:@"\"" withString:@""];
//        enc = [enc stringByReplacingOccurrencesOfString:@"'" withString:@""];
//		enc = [enc stringByReplacingOccurrencesOfRegex:@"encoding=" withString:@""];
//        NSLog(@"found encoding:%@", enc);
//	}
//	
//	enc = [enc lowercaseString];
//	//	responseEncoding = [responseEncoding lowercaseString];
//    //NSLog(@"enc = %@; responseEncoding = %@", enc, [html stringByMatching:@"encoding=(([a-zA-Z0-9-\"])*)"]);
//    
//    [html release];
//	
//    if (!enc) {
//		return @"utf-8";
//    }else if (enc) {
//        //html = [[NSString alloc] initWithData:dataBuffer encoding:[[[self encodingSet] objectForKey:enc] unsignedLongValue]];
//		return enc;
//    }
//	return enc;
//}

- (NSStringEncoding) findCorrectHtmlStringEncodingFrom:(NSData *)data andTextEncoding:(NSString *)responseEncoding
{
	NSString * encStr = [self findCorrectHtmlStringFrom:data andTextEncoding:responseEncoding];
	return (NSStringEncoding)[[_encodings objectForKey:encStr] unsignedLongValue];
}

- (NSDictionary *) fontFamily
{
	NSArray *fonts = [UIFont familyNames];
	NSMutableDictionary *allFonts = [NSMutableDictionary new];
	for (NSString * familyName in fonts) {
		[allFonts setObject:[UIFont fontNamesForFamilyName:familyName] forKey:familyName];
	}
	[allFonts writeToFile:@"/iphon4_font_family.plist" atomically:YES];
	printf("Notice! Has already written file iphon4_font_family in \"/\"");
	return XAutorelease(allFonts);
}

static NSArray *dateformatters = nil;

- (NSDate*)dateFromString:(NSString*) sDate
{
	if (dateformatters == nil) {
		dateformatters = [[NSArray alloc] initWithObjects:
						  @"EEE, dd MMM yyyy hh:mm:ss z",
						  @"EEE, dd MMM yyyy h:m:s z",
						  @"EEE, dd MMM yyyy H:m:s z",
						  @"EEE, d MMM yyyy HH:m:s z",
						  @"EEE, dd MMM yyyy",
						  @"EEE, MMM dd yyyy hh:mm:ss",
						  @"EEE, MMM dd yyyy H:mm:ss",
						  @"EEE, MMM dd yyyy H:mm:ss",
						  @"yyyy-mm-dd hh:mm:ss",
						  @"yyyy-mm-dd HH:mm:ss",
						  @"yyyy-mm-dd hh:mm:ss EEE",
						  nil];
	}
	NSDateFormatter *format =  [NSDateFormatter new];
	NSDate *date = nil;
	[format setLocale:XAutorelease([[NSLocale alloc] initWithLocaleIdentifier:@"en_US"])];
	for (int i = 0; i < [dateformatters count]; i++) {
		[format setDateFormat:[dateformatters objectAtIndex:i]];
		date = [format dateFromString:sDate];
		if (date) {
			break;
		}
	}
    XRelease(format);
	return date;
}

//- (BOOL)checkResponderIfCompressed:(NSDictionary *)responseHeaders
//{
//    NSArray * keys  = [NSArray arrayWithObjects:
//                       //@"Content-Type", @"Content-Encoding",
//                       @"Data-Encoding", nil];
//    if (responseHeaders == nil) {
//        return NO;
//    }
//    
//    NSLog(@"%s %@", __FUNCTION__, responseHeaders);
//    for (NSString * theKey in keys) {
//        NSLog(@"theKey :%@", theKey);
//        NSLog(@"value :%@", [responseHeaders valueForKey:theKey]);
//        
//        if ([responseHeaders valueForKey:theKey] == nil) {
//            continue;
//        }
//        
//        if ([[responseHeaders valueForKey:theKey] rangeOfString:@"gzip"].length > 0) {
//            NSLog(@"range :%@", NSStringFromRange([[responseHeaders valueForKey:theKey] rangeOfString:@"gzip"]));
//            return YES;
//        }
//        if ([[responseHeaders valueForKey:theKey] rangeOfString:@"x-gzip"].length > 0) {
//            NSLog(@"range :%@", NSStringFromRange([[responseHeaders valueForKey:theKey] rangeOfString:@"x-gzip"]));
//            return YES;
//        }
//    }
//    return NO;
//}


/////////////////// 打印视图层级结构
//int level = -1;
//NSMutableString * tabString = nil;
//
//- (void)resetDataForTravelingSubviews 
//{
//    SafeRelease(tabString);
//    SafeRelease(foundSubviews);
//    tabString = [NSMutableString new];
//    foundSubviews = [NSMutableArray new];
//    level = -1;
//}
//
//- (void)travelSubviews:(UIView *) view {
//    level ++;
//    [tabString appendString:@" "];
//    UIView * testView = nil;
//    for (int i = 0; i < [[view subviews] count]; i++) {
//        testView = [[view subviews] objectAtIndex:i];
//        NSLog(@"%@:%@ %@ %@", tabString, [testView class], NSStringFromCGRect(testView.frame), NSStringFromBool(testView.clipsToBounds));
//        [self travelSubviews:testView];
//    }
//    level--;
//    if (level > 0) {
//        [tabString deleteCharactersInRange:NSMakeRange(0, 1)];
//    }
//}
//
//- (void)findSubview:(UIView *)view WithName:(NSString *)name
//{
//    level ++;
//    //if (level > 0) [tabString appendString:@" "];
//    UIView * testView = nil;
//    for (int i = 0; i < [[view subviews] count]; i++) {
//        testView = [[view subviews] objectAtIndex:i];
//        if ([NSStringFromClass([testView class]) hasPrefix:name]) {
//            [foundSubviews addObject:testView];
//        }
//        //NSLog(@"%@:%@ %@;  match:%@", tabString, NSStringFromClass([testView class]), NSStringFromCGRect(testView.frame), NSStringFromBool([NSStringFromClass([testView class]) hasPrefix:name]));
//        [self findSubview:testView WithName:name];
//    }
//    level--;
//    //if (level > 0) {
//    //    [tabString deleteCharactersInRange:NSMakeRange(0, 1)];
//    //}
//}

//char * hex2dec(const char * source)
//{
//    int last_non_zero_pos, i, hex_index;
//    char * dec_string;
//    
//    /* log(16) = 1.204 */
//    const double length_rate = 1.3;
//    
//    int hex_length = strlen(source);
//    int dec_length = hex_length * length_rate + 1;
//    
//    /* Result goes here. */
//    int * dec = (int *)malloc(dec_length * sizeof(int));
//    
//    /* Value of 0x1, 0x10, 0x100, 0x1000, ... */
//    int * curr = (int *)malloc(dec_length * sizeof(int));
//    
//    for (i = 0; i < dec_length; i++)
//    {
//        dec[i] = curr[i] = 0;
//    }
//    
//    /* 0x1 = 0000000000001(10) */
//    curr[0] = 1;
//    
//    for (hex_index = 0; hex_index < hex_length; hex_index++)
//    {
//        /* Convert from right to left. */
//        int hex_pos = hex_length - 1 - hex_index;
//        char hex_curr_value = source[hex_pos];
//        int dec_curr_value, dec_index, curr_index;
//        
//        /* Convert a single hex to dec. */
//        if (hex_curr_value <= '9' && hex_curr_value >= '0')
//        {
//            dec_curr_value = hex_curr_value - '0';
//        }
//        else if (hex_curr_value <= 'f' && hex_curr_value >= 'a')
//        {
//            dec_curr_value = hex_curr_value - 'a' + 10;
//        }
//        else if (hex_curr_value <= 'F' && hex_curr_value >= 'A')
//        {
//            dec_curr_value = hex_curr_value - 'A' + 10;
//        }
//        
//        /* Add this hex to dec result. */
//        for (dec_index = 0; dec_index < dec_length; dec_index++)
//        {
//            dec[dec_index] += dec_curr_value * curr[dec_index];
//        }
//        for (dec_index = 0; dec_index < dec_length; dec_index++)
//        {
//            dec[dec_index + 1] += dec[dec_index] / 10;
//            dec[dec_index] = dec[dec_index] % 10;
//        }
//        
//        /* 0x1->0x10, 0x10->0x100, 0x100->0x1000, ... */
//        for (curr_index = 0; curr_index < dec_length; curr_index++)
//        {
//            curr[curr_index] *= 16;
//        }
//        for (curr_index = 0; curr_index < dec_length; curr_index++)
//        {
//            curr[curr_index + 1] += curr[curr_index] / 10;
//            curr[curr_index] = curr[curr_index] % 10;
//        }
//    }
//    
//    /* The output is reversed, so we should reverse it. */
//    last_non_zero_pos = dec_length - 1;
//    while (0 == dec[last_non_zero_pos])
//    {
//        last_non_zero_pos--;
//    }
//    dec_string = (char *)malloc((last_non_zero_pos + 2) * sizeof(char));
//    for (i = 0; i < last_non_zero_pos + 1; i++)
//    {
//        dec_string[i] = dec[last_non_zero_pos - i] + '0';
//    }
//    
//    free(dec);
//    free(curr);
//    
//    return dec_string;
//}

- (NSString *)httpParamsStringByArray:(NSArray *)params
{
#ifdef _REGEXKITLITE_H_
    NSMutableArray *comp = [NSMutableArray arrayWithCapacity:12];
    for (NameValuePaire *param__ in params) {
        [comp addObject:[NSString stringWithFormat:@"%@=%@", param__.name, param__.value]];
    }    
    NSString *rtn = [comp componentsJoinedByString:@"&"];
    return rtn;
#else
    NSLog(@"Warnning No _REGEXKITLITE_H_  MACRO!");
    return nil;
#endif
}

@end
